#include <cstdlib>
#include <ctime>
#include "TFControllerImpl.h"
#include "TFSoundManager.h"
#include "TFServices.h"


TFControllerImpl::TFControllerImpl()
{
	//srand should be called once
	srand((unsigned)time(NULL));
	PA_InitRand();

	_hasAI = false;
	_aiColor = RED_PLAYER;
}

TFControllerImpl::~TFControllerImpl()
{
}


bool TFControllerImpl::StartOrTouchPressed()
{
    if (Stylus.Held || Pad.Held.Start)
    {
        return true;
    }
    else
    {
        return false;
    }
}

void TFControllerImpl::WaitForPress(s16 timer)
{
	while (timer > 0 && !Stylus.Newpress && !Pad.Newpress.Start && !Pad.Newpress.B && !Pad.Newpress.A)
	{
		timer--;
        PA_WaitForVBL();
	}
}

void TFControllerImpl::HandleSplash(TF_GAME_MODE newMode)
{
	s16 timer = 480;
	if (_model->GetGameMode() != SPLASH_WARNING)
	{
		TFServices::FadeBgOut(SCREEN_BOTH);
	}
	_model->SetGameMode(newMode);
	_view->Redraw();
	TFServices::FadeBgIn(SCREEN_BOTH);
	WaitForPress(timer);
}

HRESULT TFControllerImpl::DoSplashIntro()
{
	HRESULT HR = S_OK;

	//warning screen splash
	HandleSplash(SPLASH_WARNING);
	
	//uncc splash
	HandleSplash(SPLASH_UNCC);


	//rapid dojo splash
	HandleSplash(SPLASH_LOGO);

	//main screen splash
	HandleSplash(SPLASH_MAIN);

	TFSoundManager::PlayMusic(MUSIC_BACKGROUND_INTRO);

	return HR;
}


HRESULT TFControllerImpl::ListenAndProcess()
{
	HRESULT HR = S_OK;

	//initialize control loop to the main menu
	//and draw the menu
	_model->SetGameMode(MENU);
	_view->Redraw();

	//run until an interaction
	//is detected which ends the game
	bool isRunning = true;
	while (isRunning)
	{
		switch(_model->GetGameMode())
		{
			case MENU:
				HandleMenuLoop();
				break;
			case GAME_ONEPLAYER:
				_hasAI = true;
				HandleGameLoop();
				break;
			case GAME_TWOPLAYER:
				_hasAI = false;
				HandleGameLoop();
				break;
			case PAUSE:
				//HandlePause();
				break;
			case GAME_OVER:
				//HandleGameOver();
				break;
			case RED_WINS:
				//HandleWin();
				break;
			case BLUE_WINS:
				//HandleWin();
				break;
			default:
				break;
		}

		//Tell view to redraw
		_view->Redraw();
		PA_WaitForVBL();
	}

	return HR;
}

void TFControllerImpl::HandleMenuLoop()
{
	TFMenu* menu = _model->GetMenuModel();
	while(_model->GetGameMode() == MENU)
    {
		if (Stylus.Newpress){
			/*int stylusSelect = */menu->StylusSelect(Stylus.X, Stylus.Y);
			TFSoundManager::PlaySound(SOUND_MENU_SELECT);
			TF_MENU_OPTION selectedOption = menu->GetSelectedOption();
			if(selectedOption == ONE_PLAYER)
			{
				_model->SetGameMode(GAME_ONEPLAYER);
				return;
			}else if(selectedOption == TWO_PLAYER)
			{
				_model->SetGameMode(GAME_TWOPLAYER);
				return;
			}
		}
		
		if(Pad.Newpress.Up)
        {
            menu->ChangeSelected(MENU_UP);
            TFSoundManager::PlaySound(SOUND_MENU_MOVE);
			_view->Redraw();
        }
        else if(Pad.Newpress.Down)
        {
            menu->ChangeSelected(MENU_DOWN);
            TFSoundManager::PlaySound(SOUND_MENU_MOVE);
			_view->Redraw();
        }
        else if(Pad.Newpress.Start)
        {
			TFSoundManager::PlaySound(SOUND_MENU_SELECT);
			TF_MENU_OPTION selectedOption = menu->GetSelectedOption();

			if(selectedOption == ONE_PLAYER)
			{
				_model->SetGameMode(GAME_ONEPLAYER);
				return;
			}else if(selectedOption == TWO_PLAYER)
			{
				_model->SetGameMode(GAME_TWOPLAYER);
				return;
			}

			_view->Redraw();
			PA_WaitForVBL();
		}
        PA_WaitForVBL();
    }
}



void TFControllerImpl::HandleGameLoop()
{
	//Booleans for SETUP state.
	bool placingBarricade = false;
	bool placingTroop = false;
	bool placingFlag = false;
	TF_ADD_PIECE new_piece = TF_ADD_PIECE_NULL;
	TF_PIECE_STATE new_piece_state = TF_PIECE_STATE_NULL;

	while(_model->GetGameMode() == GAME_ONEPLAYER || _model->GetGameMode() == GAME_TWOPLAYER)
    {
		if (Stylus.Newpress)
		{
			//clear error message
			PA_ClearTextBg(1);
			_view->HidePlacePieces();
		}
		int row, col;
		int buttonIndex;
		bool boardClicked=false;
		bool buttonClicked=false;
		int actionPoints = 0;

		if(_model->GetTurn() == RED_PLAYER)
		{
			PA_OutputText(1,0,1, "Player Turn: Red ");
		}
		else
		{
			PA_OutputText(1,0,1, "Player Turn: Blue");
		}

		switch(_model->GetTurnState())
		{
			case NEW_GAME:
				//PA_OutputText(1,0,2, "Mode: NEW_GAME");
				_model->NewGame();
			
			/*
				if(_model->DoInitSetup()) 
				{
					_model->RandomSetup();
					_model->SetTurnState(NEW_TURN);
					_model->DoneSetup();
					break;
				}
			*/
				_model->SetTurnState(SETUP);
				break;
		
			case SETUP:
				//PA_OutputText(1,0,2, "Mode: SETUP");
				//PA_SetTextCol(1,0,31,0);
				//PA_OutputText(1,5,18, "Please place your pieces");
				//PA_SetTextCol(1,0,0,0);
				//PA_OutputText(1,13,16, "Please");
				//PA_OutputText(1,13,17, "place");
				//PA_OutputText(1,14,18, "your");
				//PA_OutputText(1,13,19, "pieces");				
				//_view->InitPlacePieces();
				_view->ShowPlacePieces();

				if (Pad.Newpress.Start)
				{
					_view->DrawRulesScreen();
				}
				if(_model->PiecesToPlace() > 0){
					if(_hasAI && _model->GetTurn() == _aiColor)
					{ 
						if (_model->DoInitSetup())
						{
							//_ai->SetupBoard(_aiColor);
							_model->RandomSetup(_aiColor);
						}
						else
						{
							TFBoard* board = _model->GetBoard();
							_ai->PlacePieces(board, _model->GetActionPoints(), 0);
						}
					}
					if (Stylus.Newpress)
					{
						if (_view->ButtonClicked(Stylus.X, Stylus.Y, &buttonIndex) == S_OK)
						{
								if (buttonIndex == BTN_RAND)
								{									
									//random placement
									if(_model->GetTurn() == RED_PLAYER) // both setup complete
									{
										_model->RandomSetup(RED_PLAYER);
										//_model->SetTurn(BLUE_PLAYER); // blue player starts
										//_model->SetTurnState(NEW_TURN);
										//_model->DoneSetup();							
									}
									else 
									{
										_model->RandomSetup(BLUE_PLAYER);
										//_model->SetTurn(RED_PLAYER);
										//_model->SetTurnState(NEW_GAME);							
									}
									break;
								}
								if (buttonIndex == BTN_QUIT)
								{									
									//exit back to main menu
									//main screen splash
									//for now we won't confirm.. sprite hiding issues
									if (_view->GetConfirmQuit())
									{
										_view->DeInitGame();
										HandleSplash(SPLASH_MAIN);
										_model->SetGameMode(MENU);
										_model->InitializeAll();
										_view->Redraw();
										return;
									}
								}
								else if (buttonIndex == BTN_RULES)
								{
									_view->DrawRulesScreen();
								}
								else if (buttonIndex == BTN_BARRICADE)
								{
									if (_model->CanPlacePiece(BARRICADE_1))
									{
										placingBarricade=true;
										new_piece = BARRICADE;
										new_piece_state = BARRICADE_1;
									}
								}
								else if (buttonIndex == BTN_FLAG)
								{									
									if (_model->CanPlacePiece(FLAG_0))
									{										
										placingFlag=true;
										new_piece = FLAG;
										new_piece_state = FLAG_0;
									}
									else if (_model->CanPlacePiece(FLAG_BARRICADE))
									{										
										placingFlag=true;
										new_piece = FLAG_FORTIFICATION;
										new_piece_state = FLAG_BARRICADE;
									}
								}
								else if (buttonIndex == BTN_TROOP)
								{									

									if (_model->CanPlacePiece(TROOP_PIECE))
									{
										placingTroop=true;
										new_piece = TROOP_TEMP;				//Name of piece to add.
										new_piece_state = TROOP_PIECE;		//Name of piece in the queue.
									}
								}
							

						}
						else if(_view->BoardClicked(Stylus.X, Stylus.Y, &row, &col) == S_OK)
						{
							if(new_piece != TF_ADD_PIECE_NULL){
								HRESULT addPieceHR = _model->GetBoard()->AddPiece(col,row, new_piece, _model->GetTurn());
								if(addPieceHR == S_OK){
									_model->PiecePlaced(new_piece_state);

									switch(new_piece_state)
									{
									case BARRICADE_1:
										_model->SetNumBarricades(_model->GetNumBarricades() - 1);
										if (_model->GetNumBarricades() == 0)
										{
											_view->SetButtonActive(BTN_BARRICADE, false);
										}
										break;
									case FLAG_BARRICADE:										
										_model->SetNumFlags(_model->GetNumFlags() - 1);
										if (_model->GetNumFlags() == 0)
										{
											_view->SetButtonActive(BTN_FLAG, false);
										}
										break;
									case FLAG_0:					
										_model->SetNumFlags(_model->GetNumFlags() - 1);
										if (_model->GetNumFlags() == 0)
										{
											_view->SetButtonActive(BTN_FLAG, false);
										}
										break;
									case TROOP_PIECE:
										_model->SetNumTroops(_model->GetNumTroops() - 1);
										if (_model->GetNumTroops() == 0)
										{
											_view->SetButtonActive(BTN_TROOP, false);
										}
										//play sound based on color
										if (_model->GetTurn() == RED_PLAYER)
										{
											TFSoundManager::PlaySound(SOUND_PLACE_TROOP_RED);
										}
										else
										{
											TFSoundManager::PlaySound(SOUND_PLACE_TROOP_BLUE);
										}
										break;
									//default:
										//PA_OutputText(1,0,15, "ERROR: Piece not identified.");
									}

									//PA_OutputText(1,0,20, "Piece placed at x=%d y=%d", col, row);
									new_piece = TF_ADD_PIECE_NULL;
								}else{
									//give appropriate error message:
									PA_OutputText(1,0,19, "Cannot place piece!");
									switch(new_piece)
									{
									case BARRICADE:
										PA_OutputText(1,0,20, "Please place a barricade on your side!");
										break;
									case FLAG_BARRICADE:										
										PA_OutputText(1,0,20, "Please fortify an existing flag!");
										break;
									case FLAG:					
										PA_OutputText(1,0,20, "Please place a flag on the back row!");
										break;
									case TROOP_TEMP:
										PA_OutputText(1,0,20, "Please place the troop on your 1st or 2nd row!");
										break;
									default:
										PA_OutputText(1,0,15, "ERROR: Piece not identified.");
									}
									
								}
							}
						}
					}
				}else{
						if(_model->DoInitSetup())
						{
							if(_model->GetTurn() == RED_PLAYER) // both setup complete
							{
								_view->HideButton(BTN_RAND);
								_model->SetTurn(BLUE_PLAYER); // blue player starts
								_model->SetTurnState(NEW_TURN);
								_model->DoneSetup();							
							}
							else 
							{
								_model->SetTurn(RED_PLAYER);
								_model->SetTurnState(NEW_GAME);	
								_view->SetButtonActive(BTN_BARRICADE, true);
								_view->SetButtonActive(BTN_TROOP, true);
								_view->SetButtonActive(BTN_FLAG, true);
							}
						}
						else
						{
							_model->SetTurnState(NORMAL);
						}
				}
				break;
			case NEW_TURN:
				//PA_OutputText(1,0,2, "Mode: NEW_TURN");
				PA_ClearTextBg(1);
				TFSoundManager::Rumble(15,3);

				actionPoints = PA_RandMinMax(1,6);//rand()%6 +1 ;

				_model->GetGameTurn()->SetPoints(actionPoints);
				_view->UpdateActionPoints(_model->GetGameTurn()->GetPoints());
				
				_view->SetButtonActive(BTN_BARRICADE, false);
				_view->SetButtonActive(BTN_TROOP, false);
				_view->SetButtonActive(BTN_FLAG, false);
				_model->SetTurnState(NORMAL);				

				if (_hasAI && _model->GetTurn() == _aiColor)
				{
					//AI can handle this on its own
				}
				else
				{
					if(_model->GetGameTurn()->GetPoints() % 2 == 0) // Even points, so add barricade
					{
						if (_model->RoomForBarricade() == S_OK)
						{
							_model->pieces_to_place.push_back(new TFGamePiece(BARRICADE_1, _model->GetTurn(), 0));
							_model->SetTurnState(SETUP);	
							_model->SetNumBarricades(_model->GetNumBarricades() + 1);
							_view->SetButtonActive(BTN_BARRICADE, true);
						}
					}
					if(_model->GetGameTurn()->GetPoints() % 6 == 0) // 6 points, so add flag fortification
					{					
						if (_model->CanFortifyFlag() == S_OK)
						{
							_model->pieces_to_place.push_back(new TFGamePiece(FLAG_BARRICADE, _model->GetTurn(), 0));
							_model->SetTurnState(SETUP);	
							_model->SetNumFlags(_model->GetNumFlags() + 1);
							_view->SetButtonActive(BTN_FLAG, true);
						}
					}
					if(_model->CanAddTroop(_model->GetTurn()))
					{
						if (_model->RoomForTroop() == S_OK)
						{
							_model->pieces_to_place.push_back(new TFGamePiece(TROOP_PIECE, _model->GetTurn(), 0));
							_model->SetTurnState(SETUP);		
							_model->TakeTroop(false, _model->GetTurn());
							_model->SetNumTroops(_model->GetNumTroops() + 1);
							_view->SetButtonActive(BTN_TROOP, true);
						}
					}
				}
				break;
			case NORMAL:
				//PA_OutputText(1,0,2, "Mode: NORMAL");
				//if NOT the AI's turn
				_view->HidePlacePieces();
				if( !(_model->GetTurn() == _aiColor && _hasAI) )
				{					
					// GET INPUT HERE FROM VIEW
					//        ********
					//PA_OutputText(1,0,3, "Action Points: %d", _model->GetGameTurn()->GetPoints());
					if (Pad.Newpress.Start)
					{
						_view->DrawRulesScreen();
					}
					if (Stylus.Newpress)
					{
						PA_WaitForVBL();						

						if (_view->BoardClicked(Stylus.X, Stylus.Y, &row, &col) == S_OK)
						{
							boardClicked=true;
							
							if(_model->GetBoard()->GetPieceAt(col,row)->GetPiece() == TROOP_PIECE)
								PA_OutputText(1,0,15, "Troop Moves Remaining: %d", _model->GetBoard()->GetPieceAt(col,row)->GetPoints());
							else
								PA_OutputText(1,0,15, "Troop Moves Remaining:  ");
							PA_WaitForVBL();
						}
						else
						{
							if (_view->ButtonClicked(Stylus.X, Stylus.Y, &buttonIndex) == S_OK)
							{
								//index of button clicked
								buttonClicked=true;
								//PA_OutputText(1,0,11, "button %d selected", buttonIndex);
							}
						}
						// GET INPUT HERE FROM VIEW

						if (buttonClicked)
						{
							if (buttonIndex == BTN_QUIT)
							{
								//exit back to main menu
								//main screen splash
								//for now we won't confirm.. sprite hiding issues
								if (_view->GetConfirmQuit())
								{
									_view->DeInitGame();
									HandleSplash(SPLASH_MAIN);
									_model->SetGameMode(MENU);
									_model->InitializeAll();
									_view->Redraw();
									return;
								}
							}
							else if (buttonIndex == BTN_RULES)
							{
								_view->DrawRulesScreen();
							}
						}

						if(_model->GetSelected() == NOT_SELECTED && boardClicked) // Nothing has been selected yet
						{
							//make sure its the right color troop
							if (_model->GetBoard()->GetPieceAt(col,row)->GetColor() == _model->GetTurn())
							{
								PA_WaitForVBL();
								_model->GetGameMove()->SetX1(col); // Starting cords
								_model->GetGameMove()->SetY1(row);
								_model->SetSelected(SELECTED);
                                TFSoundManager::PlaySound(SOUND_SELECT_PIECE);
							}
							//_view->DrawPieceLocation(col, row, true);
						}
						else if(_model->GetSelected() == SELECTED && boardClicked) // Something already selected
						{						
							PA_WaitForVBL();
							_model->GetGameMove()->SetX2(col); // Destination cords
							_model->GetGameMove()->SetY2(row);

							_model->GetGameTurn()->SetMove(_model->GetGameMove());
							_model->GetGameTurn()->SetTurn(_model->GetTurn());

							_model->GetBoard()->MoveTroop(_model->GetGameTurn());

							_view->UpdateActionPoints(_model->GetGameTurn()->GetPoints());		
/*
							//Check end of game
							switch(_model->GetBoard()->GameOverTest())
							{
								case NO_WINNER:
									{
										break;
									}
								case BLUE_WINNER:
									{
										PA_ClearTextBg(1);
										PA_OutputText(1,9,9, "BLUE WINS!!!");
										_model->SetTurnState(END);
										break;
									}
								case RED_WINNER:
									{
										PA_ClearTextBg(1);
										PA_OutputText(1,9,9, "RED WINS!!!");
										_model->SetTurnState(END);
										break;
									}
							}
*/

							// Switch turns after all Action Points have been used
							if(_model->GetGameTurn()->GetPoints() == 0)
							{							
								if(_model->GetTurn() == BLUE_PLAYER)
									_model->SetTurn(RED_PLAYER);
								else
									_model->SetTurn(BLUE_PLAYER);	

								_model->SetTurnState(NEW_TURN);
								_model->GetBoard()->ResetPiecePoints();
							}
							else if(_model->GetGameTurn()->GetPoints() < 0)
							{
								PA_OutputText(1,0,9, "ERROR: Points less than 0");
								PA_WaitForVBL();
							}							

							//_view->DrawPieceLocation(_model->GetGameMove()->GetX1(), _model->GetGameMove()->GetY1(), false);
							//_view->DrawPieceLocation(col, row, false);

							_model->SetSelected(NOT_SELECTED);
						}else
						{
							//PA_OutputText(1,0,9, "ERROR: SELECTED/NOT_SELECTED not set");
							PA_WaitForVBL();
						}
					}
				}else
				{
					//AI turn
					TFGameMoveList oListOfMoves;
					_ai->DoTurn(_model->GetGameTurn()->GetPoints(), oListOfMoves);
					
					int moveCount = oListOfMoves.Size(); 

					//PA_OutputText(1,0,9, "points ... moves   %d %d",_model->GetGameTurn()->GetPoints(), moveCount);
					for(int j = 0; j < moveCount; j++)
					{
						TFGameMove tempMove;
						oListOfMoves.Get(j, tempMove);
						//PA_OutputText(1,0,1, "x,y,x,y.. moves   %d %d %d %d",tempMove._x1, tempMove._y1,tempMove._x2, tempMove._y2);
					
						_model->GetGameTurn()->SetMove(&tempMove);
						_model->GetGameTurn()->SetTurn(_aiColor);
						_model->GetBoard()->MoveTroop(_model->GetGameTurn(), false);
						
						_view->UpdateActionPoints(_model->GetGameTurn()->GetPoints());	

						//draw change
						_view->Redraw();

						//make a delay after each move
						for(int p = 0; p < 100; p++)
						{
							PA_WaitForVBL();
						}
					}
					
					//end turn
					_model->SetTurnState(NEW_TURN);
					_model->GetBoard()->ResetPiecePoints();
					_model->SetSelected(NOT_SELECTED);
					if(_model->GetTurn() == BLUE_PLAYER)
						_model->SetTurn(RED_PLAYER);
					else
						_model->SetTurn(BLUE_PLAYER);
				}
	
				//check for a win condition
				switch(_model->GetBoard()->GameOverTest())
				{
					case NO_WINNER:
						{
							break;
						}
					case BLUE_WINNER:
						{
							_view->DeInitGame();
							_view->DisplayWinScreen(BLUE_PLAYER);
							//once that breaks out, quit game
							HandleSplash(SPLASH_MAIN);
							_model->SetGameMode(MENU);
							_model->InitializeAll();
							_view->Redraw();
							break;
						}
					case RED_WINNER:
						{
							_view->DeInitGame();
							_view->DisplayWinScreen(RED_PLAYER);
							//once that breaks out, quit game
							HandleSplash(SPLASH_MAIN);
							_model->SetGameMode(MENU);
							_model->InitializeAll();
							_view->Redraw();
							break;
						}
				}

				break;
			case END:
				//change game mode here
				break;
		}//end switch

		_view->Redraw();
		PA_WaitForVBL();
	}
}
